///////////////////////////////////////////////////////////
// Filename: findapi.js                                  //
///////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////
// Dependencies:                                                     //
// timespan.js - for keeping track of elapsed time during session.   //
// forceClose() function must be defined in the including document,  //
//              or replace call to forceClose with an equivalent     //
//              call that closes the lesson window.                  //
// Netscape 4.5 - 4.75 OR Microsoft Internet Explorer 4.01 - 6.0     //
///////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////
// Purpose:                                              //
// Find the LMS API Adapter (will be null if not found), //
// and define API wrapper functions.  If the API         //
// Adapter is not found, then act appropriately by       //
// either closing the lesson window, or allowing the     //
// lesson to continue in its absence.                    //
///////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
// Wrapper Functions:                                            //
// String LMSInitialize()                                        //
// String LMSFinish()                                            //
// String LMSSetValue(String data_model_element, String value)   //
// String LMSGetValue(String data_model_element)                 //
// String LMSCommit()                                            //
// String LMSGetLastError()                                      //
// String LMSGetErrorString(String errorNumber)                  //
// String LMSGetDiagnostic(Optional String errorNumber)          //
///////////////////////////////////////////////////////////////////

// SCORM_DEBUG causes error messages to be displayed if any
// API Adapter errors are encountered after any API call made.
var SCORM_DEBUG = true;
// SCORM_CRITICAL causes the lesson to be closed if any
// API Adapter errors are encountered after any API call made.
var SCORM_CRITICAL = false;
// DISPLAY_DIAGNOSTIC is a switch that allows information from
// LMSGetDiagnostic() to be displayed in error messages.  If 
// is set to false, LMSGetDiagnostic() will not be called
// when displaying error messages.
var DISPLAY_DIAGNOSTIC = false;

var API = null;

// sessionTime is TimeSpan object 
var sessionTime = null;
// inLMSFinish is a flag that prevents the LMSFinish wrapper
// from being called twice.
var inLMSFinish = false;

var ABORT = false;
var enableCommit = true;

// APILocation and APIWin are used to keep track of the window
// and document location that the API Adapter was found in.
// This information is then used to verify the existance of
// the API Adapter before any API Adapter function call is made
// from within a wrapper function (via a call to checkForAPIAdapter()).
var APILocation = "";
var APIWin = null;

// FindAPI() is a recursive function that is used to locate
// the API Adapter.
function FindAPI(win)
{
 	if (win.API != null)
	{
		APIWin = win;
		APILocation = APIWin.document.location;
		return win.API;
	}
	else 
	{
		if (win.parent != null)
		{
			if (win.parent != win)
			{
				APIWin = win;
				APILocation = APIWin.document.location;
				return FindAPI(win.parent);
			}
			else
			{	
				if (win.opener != null)
				{
					APIWin = win;
					APILocation = APIWin.document.location;
					return FindAPI(win.opener)
				}
			}
		}
	}

	return null;
}

// obtain the API Adapter reference
API = FindAPI(window);

// verify the existance of the API Adapter, and take any action needed.
if (API == null && SCORM_CRITICAL)
{
	alert("FATAL ERROR: Cannot locate SCORM API object. \nThis lesson will now be closed.");
	parent.window.close();
}

//////////////////////////////
// Error Trapping Functions //
//////////////////////////////

// APIAdapterError() is temporarily assigned as the window's error
// handling routine in the body of checkForAPIAdapter().
function APIAdapterError()
{
	// This function only gets called when there is an error
	// while attempting to verify the existance of the API Adapter.
	// Such circumstances require that the lesson window be closed
	// so students do not continue to interact with the courseware untethered.
	alert("ERROR:\n\nThe SCORM API Adapter is missing.  This lesson will now close.\n\nThis error has occurred because you have either closed or navigated out of a page required by the LMS.  To avoid this error in future lesson sessions, do not close or navigate out of any web page opened by the LMS.");
	executeClose();
	return true;
}

// executeClose() gets called when the lesson window needs to be closed.
function executeClose()
{
	ABORT = true;
	setTimeout("forceClose()",1000);
}

// checkForAPIAdapter() gets called before any API Adapter function
// is directly called.  checkForAPIAdapter() checks to make sure
// that the API Adapter is still present; if it is not present
// executeClose() is called to close the lesson window.
function checkForAPIAdapter()
{
	var flag = false;
	var oldErrorHandler = null;

	// Remember old error handlers, and assign
	// APIAdapterError() as the new one.
	if (navigator.appName == "Microsoft Internet Explorer")
	{
		oldErrorHandler = self.onerror;
		self.onerror = APIAdapterError;
	}
	else
	{
		oldErrorHandler = window.onerror;
		window.captureEvents(Event.onerror);
		window.onerror = APIAdapterError;
	}

	// Perform a series of checks that will verify
	// the existance of the API Adapter.
	//
	// Check to see if window is null.
	if (APIWin == null) flag = true;
	// Check to see if the API window is closed.
	else if (APIWin.closed == true) flag = true;
	// Check to see if the document in the API window is null.
	else if (APIWin.document == null) flag = true;
	// Check to see if the location of the document in the API window is null.
	else if (APIWin.document.location == null) flag = true;
	// Check to see if the location of the document in the API window is
	// the same as it was when the API Adapter was originally located.
	else if (APIWin.document.location != APILocation) flag = true;

	// Restore the error handling routine back to what it was before.
	if (navigator.appName == "Microsoft Internet Explorer")
	{
		self.onerror = oldErrorHandler;
	}
	else
	{
		window.onerror = oldErrorHandler;
	}

	// If the flag has been set by any of the above checks, then
	// display an error message and call executeClose() to close the lesson window.
	if (flag)
	{
		alert("ERROR:\n\nThe SCORM API Adapter is missing.  This lesson will now close.\n\nThis error has occurred because you have either closed or navigated out of a page required by the LMS.  To avoid this error in future lesson sessions, do not close or navigate out of any web page opened by the LMS.");
		executeClose();
		// There was a problem, so return false.
		return false;
	}
	else
	{
		// Everything went well, so return true.
		return true;
	}
}

///////////////////////////
// API Wrapper Functions //
///////////////////////////

function LMSInitialize()
{
	if (ABORT) return;
	sessionTime = new TimeSpan();
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		var retVal = API.LMSInitialize("");
		var lastError = LMSGetLastError();
		if (lastError != 0 && SCORM_CRITICAL)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic());
			}
			else
			{ 
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError));
			}
			ABORT = true;
			executeClose();
			return "false";
		}
		else if (lastError != 0 && SCORM_DEBUG)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic());
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError));
			}
			return "false";
		}
		return retVal;
	}
	else
	{
		return "true";
	}
}

function LMSFinish()
{
	if (ABORT) return;
	
	if (!inLMSFinish)
	{
		inLMSFinish = true;
		LMSSetValue("cmi.core.session_time",sessionTime.getElapsed(CMITIMESPAN));
		LMSSetValue("cmi.core.exit","suspend");
		if (API != null)
		{
			if (!checkForAPIAdapter()) return "false";
			return API.LMSFinish("");
		}
		else
		{
			return "true";
		}
	}
}

function LMSGetValue(element)
{
	if (ABORT) return;
	
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		var retVal = API.LMSGetValue(element);
		var lastError = LMSGetLastError();
		if (lastError != 0 && SCORM_CRITICAL)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic() + "\nThis lesson will now be closed.");
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\nThis lesson will now be closed.");
			}
			LMSFinish();
			ABORT = true;
			executeClose();
		}
		else if (lastError != 0 && SCORM_DEBUG)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic());
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError));
			}
		}
		return retVal;
	}
	else
	{
		return "";
	}
}

function LMSSetValue(element, value) 
{
	if (ABORT) return;
	
	var retVal = "true";

	// If the lesson has already been marked complete, then
	// the code below will prevent the lesson status from
	// being changed.
	if (element == "cmi.core.lesson_status" && getVar("COMPLETE") == "1")
	{
		return "true";
	}

	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		retVal = API.LMSSetValue(element, value);
		var lastError = LMSGetLastError();
		if (lastError != 0 && SCORM_CRITICAL)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic() + "\nThis lesson will now be closed.");
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\nThis lesson will now be closed.");
			}
			LMSFinish();
			ABORT = true;
			executeClose();
		}
		else if (lastError != 0 && SCORM_DEBUG)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic());
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError));
			}
		}

		if (retVal == "true")
		{
			// if (enableCommit) API.LMSCommit("");
			// Check to see if the lesson is being marked complete.  If it is
			// then set a flag.
			if (element == "cmi.core.lesson_status" && (value == "passed" || value == "completed" || value == "failed"))
			{
				setVar("COMPLETE","1");
			}
		}
		
		return retVal;
	}
	return retVal;
}

function LMSCommit()
{
	if (ABORT) return;
	if (!enableCommit) return;
	
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		var retVal = API.LMSCommit("");
		var lastError = LMSGetLastError();
		if (lastError != 0 && SCORM_CRITICAL)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic() + "\nThis lesson will now be closed.");
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\nThis lesson will now be closed.");
			}
			
			LMSFinish();
			ABORT = true;
			executeClose();
		}
		else if (lastError != 0 && SCORM_DEBUG)
		{
			if (DISPLAY_DIAGNOSTIC)
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError) + "\n" + LMSGetDiagnostic());
			}
			else
			{
				alert("FATAL SCORM ERROR: " + LMSGetErrorString(lastError));
			}
		}
		return retVal;
	}
	else
	{
		return "true";
	}
}

function LMSGetLastError()
{
	if (ABORT) return;
	
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		return API.LMSGetLastError();
	}
	else
	{
		return "0";
	}
}

function LMSGetErrorString(errornumber)
{
	if (ABORT) return;
	
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		return API.LMSGetErrorString(errornumber + "");
	}
	else
	{
		return "No errors detected";
	}
}

function LMSGetDiagnostic(parameter)
{
	if (ABORT) return;
	
	if (API != null)
	{
		if (!checkForAPIAdapter()) return "false";
		if (parameter == null)
		{
			return API.LMSGetDiagnostic("");
		}
		else
		{
			return API.LMSGetDiagnostic(parameter + "");
		}
	}
	else
	{
		return "No errors detected";
	}
}


